﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;

namespace Pixysoft.MultiThread
{
    /// <summary>
    /// http://www.cnblogs.com/panjun-donet/archive/2008/09/04/1284700.html
    /// </summary>
    public class AsyncInvoker
    {
        public delegate void VoidAsyncInvoker();

        /// <summary>
        /// 用户指定回调函数
        /// </summary>
        /// <param name="invoker"></param>
        /// <param name="callback"></param>
        /// <returns></returns>
        public static IAsyncResult Invoke(VoidAsyncInvoker invoker, AsyncCallback callback)
        {
            if (invoker == null)
                return null;

            return invoker.BeginInvoke(callback, invoker);
        }

        /// <summary>
        /// 用户不制定回调
        /// </summary>
        /// <param name="invoker"></param>
        public static IAsyncResult Invoke(VoidAsyncInvoker invoker)
        {
            if (invoker == null)
                return null;

            return invoker.BeginInvoke(new AsyncInvoker().InvokeCallback, invoker);
        }

        private void InvokeCallback(IAsyncResult ar)
        {
            ((VoidAsyncInvoker)ar.AsyncState).EndInvoke(ar);
        }
    }

    public class AsyncInvoker<T>
    {
        public delegate void GenericAsyncInvoker(T value);

        /// <summary>
        /// 用户指定回调函数
        /// </summary>
        /// <param name="invoker"></param>
        /// <param name="callback"></param>
        /// <returns></returns>
        public static IAsyncResult Invoke(GenericAsyncInvoker invoker, T value, AsyncCallback callback)
        {
            if (invoker == null)
                return null;

            return invoker.BeginInvoke(value, callback, invoker);
        }

        /// <summary>
        /// no callback
        /// </summary>
        /// <param name="invoker"></param>
        public static IAsyncResult Invoke(GenericAsyncInvoker invoker, T value)
        {
            if (invoker == null)
                return null;

            return invoker.BeginInvoke(value, new AsyncInvoker<T>().InvokeCallback, invoker);
        }

        private void InvokeCallback(IAsyncResult ar)
        {
            ((GenericAsyncInvoker)ar.AsyncState).EndInvoke(ar);
        }
    }

    //异步模式一 同步线程中等待异步结束 结果是：主线程等待异步线程
    class tutorial_async_1
    {
        delegate void AsyncEventHandler();
        void Event1()
        {
            Console.WriteLine("Event1 Start");
            for (int i = 0; i < 5; i++)
            {
                Console.WriteLine("event1." + i);
                Thread.Sleep(100);
            }
            Console.WriteLine("Event1 End");
        }
        void Event2()
        {
            Console.WriteLine("Event2 Start");
            int i = 1;
            while (i < 5)
            {
                i = i + 1;
                Console.WriteLine("event2." + i.ToString());
            }
            Console.WriteLine("Event2 End");
        }
        void CallbackMethod(IAsyncResult ar)
        {
            ((AsyncEventHandler)ar.AsyncState).EndInvoke(ar);
        }
        void Main()
        {
            tutorial_async_1 c = new tutorial_async_1();
            AsyncEventHandler asy = new AsyncEventHandler(c.Event1);
            IAsyncResult ia = asy.BeginInvoke(null, null);
            c.Event2();
            asy.EndInvoke(ia);//这个表示要等待异步完成才继续

            //Event2 Start
            //Event1 Start
            //event1.0
            //event1.1
            //event1.2
            //event1.3
            //event1.4
            //Event1 End
            //event2.2
            //event2.3
            //event2.4
            //event2.5
            //Event2 End
        }
        void Main2()
        {
            // not support
        }
    }

    //异步模式二 异步线程自动停止异步结束 结果是：主线程不等待异步线程
    class tutorial_async_2
    {
        delegate void AsyncEventHandler();
        void Event1()
        {
            Console.WriteLine("Event1 Start");
            for (int i = 0; i < 5; i++)
            {
                Console.WriteLine("event1." + i);
                Thread.Sleep(100);
            }
            Console.WriteLine("Event1 End");
        }
        void Event2()
        {
            Console.WriteLine("Event2 Start");
            int i = 1;
            while (i < 5)
            {
                i = i + 1;
                Console.WriteLine("event2." + i.ToString());
            }
            Console.WriteLine("Event2 End");
        }
        void CallbackMethod(IAsyncResult ar)
        {
            ((AsyncEventHandler)ar.AsyncState).EndInvoke(ar);
        }
        void Main()
        {
            tutorial_async_2 c = new tutorial_async_2();
            AsyncEventHandler asy = new AsyncEventHandler(c.Event1);
            IAsyncResult ia = asy.BeginInvoke(CallbackMethod, asy);
            c.Event2();

            //RESULT::
            //Event2 Start
            //Event1 Start
            //event1.0
            //event2.2
            //event2.3
            //event2.4
            //event2.5
            //Event2 End       
        }
        void Main2()
        {
            tutorial_async_2 c = new tutorial_async_2();
            AsyncInvoker.Invoke(c.Event1);
            c.Event2();
        }
    }

    //异步模式三 使用iscomplete
    class tutorial_async_3
    {
        delegate void AsyncEventHandler();
        void Event1()
        {
            Console.WriteLine("Event1 Start");
            for (int i = 0; i < 5; i++)
            {
                Console.WriteLine("event1." + i);
                Thread.Sleep(100);
            }
            Console.WriteLine("Event1 End");
        }
        void Event2()
        {
            Console.WriteLine("Event2 Start");
            int i = 1;
            while (i < 5)
            {
                i = i + 1;
                Console.WriteLine("event2." + i.ToString());
            }
            Console.WriteLine("Event2 End");
        }
        void CallbackMethod(IAsyncResult ar)
        {
            ((AsyncEventHandler)ar.AsyncState).EndInvoke(ar);
        }
        void Main()
        {
            tutorial_async_3 c = new tutorial_async_3();
            AsyncEventHandler asy = new AsyncEventHandler(c.Event1);
            IAsyncResult ia = asy.BeginInvoke(CallbackMethod, asy);
            c.Event2();
            while (!ia.IsCompleted)
            {
            }
            //RESULT::
            //Event2 Start
            //Event1 Start
            //event1.0
            //event2.2
            //event2.3
            //event2.4
            //event2.5
            //Event2 End
            //event1.1
            //event1.2
            //event1.3
            //event1.4
            //Event1 End     
        }
        void Main2()
        {
            tutorial_async_3 c = new tutorial_async_3();
            IAsyncResult ia = AsyncInvoker.Invoke(c.Event1);
            c.Event2();
            while (!ia.IsCompleted)
            {
            }
        }
    }

    //异步模式四 使用asyncwaithandle
    class tutorial_async_4
    {
        delegate void AsyncEventHandler();
        void Event1()
        {
            Console.WriteLine("Event1 Start");
            for (int i = 0; i < 5; i++)
            {
                Console.WriteLine("event1." + i);
                Thread.Sleep(100);
            }
            Console.WriteLine("Event1 End");
        }
        void Event2()
        {
            Console.WriteLine("Event2 Start");
            int i = 1;
            while (i < 5)
            {
                i = i + 1;
                Console.WriteLine("event2." + i.ToString());
            }
            Console.WriteLine("Event2 End");
        }
        void CallbackMethod(IAsyncResult ar)
        {
            ((AsyncEventHandler)ar.AsyncState).EndInvoke(ar);
        }
        void Main()
        {
            tutorial_async_4 c = new tutorial_async_4();
            AsyncEventHandler asy = new AsyncEventHandler(c.Event1);
            IAsyncResult ia = asy.BeginInvoke(CallbackMethod, asy);
            c.Event2();
            ia.AsyncWaitHandle.WaitOne();
            //RESULT::
            //Event2 Start
            //Event1 Start
            //event1.0
            //event2.2
            //event2.3
            //event2.4
            //event2.5
            //Event2 End
            //event1.1
            //event1.2
            //event1.3
            //event1.4
            //Event1 End     
        }
        void Main2()
        {
            tutorial_async_4 c = new tutorial_async_4();
            IAsyncResult ia = AsyncInvoker.Invoke(c.Event1);
            c.Event2();
            ia.AsyncWaitHandle.WaitOne();
        }
    }

    //双异步等待
    class tutorial_async_5
    {
        delegate void AsyncEventHandler();
        IAsyncResult ar = null;
        AsyncEventHandler handler = null;
        bool created = false;


        public void test()
        {
            //我启动一个异步 由另外一个异步关闭
            handler = new AsyncEventHandler(Call);
            this.ar = handler.BeginInvoke(null, null);
            Console.WriteLine("done" + created);
        }

        private void Call()
        {
            Console.WriteLine("call another async method:: create msn conversation.");

            AsyncInvoker.Invoke(Invoke, InvokeCallback);
        }

        private void Invoke()
        {
            //send msn create here. this method is in dll. not mine.

            Console.WriteLine("creating msn conversation.");
        }

        private void InvokeCallback(IAsyncResult iar)
        {
            //get msn create response. this method is in dll. not mine

            (iar.AsyncState as AsyncInvoker.VoidAsyncInvoker).EndInvoke(iar);

            InvokeReturn();
        }

        private void InvokeReturn()
        {
            //delegate, this method is mine.

            Console.WriteLine("msn conversation created.");

            created = true;

            Callback(ar);
        }

        void Callback(IAsyncResult ar)
        {
            Console.WriteLine("stop waiting.");

            handler.EndInvoke(ar);
        }
    }
}
